
SamplerComparisonState ShadowSampler
{
   // sampler state
   Filter = MIN_MAG_LINEAR_MIP_POINT;
   AddressU = MIRROR;
   AddressV = MIRROR;

   // sampler comparison state
   ComparisonFunc = LESS;
   Filter = COMPARISON_MIN_MAG_LINEAR_MIP_POINT;
};

float calcPCFShadow(Texture2D shadowMap, float2 texCoord, float depth, float texelSize)
{
	float shadowFactor = 0.0f;
	const int pcfKernelHalfSize = 1;
	const float pcfKernelNumSamplesInv = 1.0f / ( (2 * pcfKernelHalfSize + 1) * (2 * pcfKernelHalfSize + 1) );
	for(float x = -pcfKernelHalfSize; x <= pcfKernelHalfSize; x += 1.f)
	{
		for(float y = -pcfKernelHalfSize; y <= pcfKernelHalfSize; y += 1.f)
		{
			shadowFactor += shadowMap.SampleCmpLevelZero(ShadowSampler, texCoord + float2(x, y) * texelSize, depth - 0.000001f);
		}
	}
	shadowFactor *= pcfKernelNumSamplesInv;
	return shadowFactor;
}

float calculateShadowFactor(Texture2D shadowMap, float4 lightSpacePos)
{
	lightSpacePos = lightSpacePos / lightSpacePos.w;
	const float2 texCoord = (lightSpacePos.xy * float2(0.5f, -0.5f) + float2(0.5f, 0.5f));
	return calcPCFShadow(shadowMap, texCoord, lightSpacePos.z, 1.0f / 512.0f);
	//return shadowMap.SampleCmpLevelZero(ShadowSampler, smTexCoord, depth - 0.000001f);
}

#ifndef NUM_CASCADES
#define NUM_CASCADES 4
#endif

#ifndef CASCADE_MAP_SIZE
#define CASCADE_MAP_SIZE 1024
#endif

float calculateShadowFactorCSM(Texture2D shadowMap, float2 texCoordBase, float4 lightSpacePos)
{
	lightSpacePos = lightSpacePos / lightSpacePos.w;
	const float2 texCoord = texCoordBase + (lightSpacePos.xy * float2(0.5f, -0.5f) + float2(0.5f, 0.5f)) * 0.5f;
	return calcPCFShadow(shadowMap, texCoord, lightSpacePos.z, 0.5f / CASCADE_MAP_SIZE);
	//return shadowMap.SampleCmpLevelZero(ShadowSampler, smTexCoord, depth);
}